package com.wlit.alarm.service;

import com.wlit.alarm.MainFrame;
import com.wlit.alarm.utils.CommPortUtils;
import com.wlit.alarm.utils.SmsUtils;
import gnu.io.*;
import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
import org.apache.log4j.Logger;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * 报警服务
 */
public class AlarmServiceImpl implements IAlarmService, SerialPortEventListener {

    private static Logger logger = Logger.getLogger(AlarmServiceImpl.class);

    private CommPortIdentifier listenIden;
    private SerialPort listenPort;
    private InputStream listenIs;

    private int retryTime;// 重试次数
    private boolean blnOpen = false;// 状态，是否打开

    private String portName;
    private int shudu = 115200;
    private int weishu = SerialPort.DATABITS_8;
    private int stop = SerialPort.STOPBITS_1;
    private int jiou = SerialPort.PARITY_NONE;

    private long time_start;

    private MainFrame mainFrame;

    public AlarmServiceImpl(MainFrame mainFrame){
        this.mainFrame = mainFrame;

    }

    @Override
    public synchronized void send(byte[] data) {

        if (listenPort == null && this.portName != null) {
            open(this.portName);
        }
        logger.info("send>>"+ByteBufUtil.hexDump(data));

        try {
            time_start = System.currentTimeMillis();
            CommPortUtils.sendToPort(listenPort, data);
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    @Override
    public synchronized void open(String portName) {
        this.portName = portName;
        try {
            listenIden = CommPortIdentifier.getPortIdentifier(portName);
        } catch (NoSuchPortException e) {
            logger.error("No such port error:"+portName);
            e.printStackTrace();
            return;
        }
        CommPort commPort = null;
        try {
            commPort = listenIden.open(portName, 5000);
        } catch (PortInUseException e) {
            logger.error("Port in use error:"+portName);
            e.printStackTrace();
            return;
        }
        try {
            if (commPort instanceof SerialPort) {
                listenPort = (SerialPort) commPort;
                listenIs = listenPort.getInputStream();
                listenPort.notifyOnDataAvailable(true);/*数据可用*/
                listenPort.setSerialPortParams(shudu, weishu, stop, jiou);
                listenPort.addEventListener(this);
            }
            this.blnOpen = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public synchronized void close() {

        this.blnOpen = false;
        if (listenPort != null) {
            try {
                listenPort.notifyOnDataAvailable(false);
                listenPort.removeEventListener();
            } catch (Exception e1) {
                e1.printStackTrace();
            }
        }
        if (listenIs != null) {
            try {
                listenIs.close();
                listenIs = null;
            } catch (Exception e1) {
                e1.printStackTrace();
            }
        }

        if (listenPort != null) {
            try {
                listenPort.close();
                listenPort = null;
            } catch (Exception e1) {
                e1.printStackTrace();
            }
        }
    }

    public boolean isOpen() {
        return blnOpen;
    }

    /**
     * 从流中读取
     * @param is
     * @return
     * @throws Exception
     */
    public static byte[] readFromStream(InputStream is) throws Exception{
        List<byte[]> bytesList = new ArrayList<>();

        int len = is.available();//获得数据长度
        while (len != 0) {
            byte[] bytes = new byte[len];//初始化byte数组
            is.read(bytes);
            bytesList.add(bytes);
            len = is.available();
        }
        return splicingArrays(bytesList);
    }

    /**
     * 多个数组合并
     * @param bytes
     * @return
     */
    public static byte[] splicingArrays(List<byte[]> bytes) {
        int length = 0;
        for (byte[] b : bytes) {
            length += b.length;
        }
        int interimLength = 0;
        byte[] result = new byte[length];
        for (byte[] b : bytes) {
            System.arraycopy(b, 0, result, interimLength, b.length);
            interimLength += b.length;
        }
        return result;
    }


    @Override
    public void serialEvent(SerialPortEvent arg0) {
        logger.info("serialEvent>>"+arg0.getEventType()+" "+arg0.getNewValue()+ " "+arg0.getOldValue());
        if(arg0.getEventType() == SerialPortEvent.DATA_AVAILABLE) {
            try {
                byte[] buf = readFromStream(listenIs);

                if (buf!=null && buf.length>0) {
                    logger.info("读取数据:" + ByteBufUtil.prettyHexDump(Unpooled.wrappedBuffer(buf)));
                    doRcvDeviceData(buf);
                }

            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        logger.info("耗时:"+(System.currentTimeMillis()-time_start)+"毫秒");
    }


    public void doRcvDeviceData(byte[] rcvBuf) {
        int index;
        int _serialIndex = 0;
        if (rcvBuf[0] == 0x7b && rcvBuf[1] == 0x7b && rcvBuf[2] == 0x7b) {
            index = 4;
            int dataLen = rcvBuf[index] * 0x100;
            index++;
            dataLen += rcvBuf[index++];


            int i32Temp = 0;
            int cmd = rcvBuf[index++];
            String str = "";

            //================0xFE指令=====================
            if (rcvBuf[3] == 0xfe)  //开关量，电话等配置指令
            {
                switch (cmd) {
                    case 0x02:
                    case 0x03:
                    case 0x04:
                    case 0x07:
                    case 0x08:
                    case 0x0a:
                    case 0x0c:
                    case 0x0d:

                    case 0x13:
                    case 0x15:
                        if (rcvBuf[index++] == 0) {
                            mainFrame.showInfo("Error\r\n");
                        } else {
                            mainFrame.showInfo("OK\r\n");
                        }
                        _serialIndex = 0;
                        return;
                    case 0x0e:
                        if (rcvBuf[index++] == 0) {
                            mainFrame.showInfo("设置已处于挂断状态\r\n");
                        } else {
                            mainFrame.showInfo("挂断成功\r\n");
                        }
                        _serialIndex = 0;
                        return;

                    case 0x0f:  //语音
                        if (rcvBuf[index] == 0) {
                            mainFrame.showInfo(">>语音数据无效，不能完成指令，请检查\r\n");
                        } else if (rcvBuf[index] == 1) {
                            mainFrame.showInfo(">>语音数据已接受，正在执行指令\r\n");
                        } else if (rcvBuf[index] == 2) {
                            mainFrame.showInfo(">>对方没有接电话\r\n");
                        } else if (rcvBuf[index] == 3) {
                            mainFrame.showInfo(">>拨号中，等待对方接听电话\r\n");
                        } else if (rcvBuf[index] == 4) {
                            mainFrame.showInfo(">>电话已接通，正在通话中\r\n");
                        } else if (rcvBuf[index] == 5) {
                            mainFrame.showInfo(">>电话已挂断\r\n");
                        }
                        _serialIndex = 0;
                        return;
                }
            }

            //================0xFF指令=====================
            switch (cmd) {
                case 0x00:  //读取当前配置返回
                    int iTemp = rcvBuf[index++];
                    iTemp = (iTemp * 0x100);
                    iTemp = (iTemp + rcvBuf[index]);
                    index++;
                    str = new String(rcvBuf, index, iTemp);
                    mainFrame.showInfo(str);
                    _serialIndex = 0;
                    return;

                case 0x01:
                case 0x02:
                case 0x03:
                case 0x04:
                case 0x05:
                case 0x07:
                case 0x0A:
                case 0x0b:
                case 0x10:
                case 0x16:
                case 0x19:
                case 0x20:
                case 0x22:
                case 0x25:
                case 0x28:
                case 0x32:
                case 0x33:
                case 0x34:
                case 0x3B:
                case 0x3C:
                default:
                    if (rcvBuf[index++] == 0) {
                        mainFrame.showInfo("Error\r\n");
                    } else {
                        mainFrame.showInfo("OK\r\n");
                    }
                    _serialIndex = 0;
                    return;

                case 0x06:
                    int iTemp2 = rcvBuf[index++];
                    str = "当前信号=" + iTemp2 + "\r\n";

                    mainFrame.showInfo(str);
                    _serialIndex = 0;
                    return;
                case 0x08:
                    iTemp = rcvBuf[index++];
                    iTemp = (iTemp & 0x7f);//取提最高位
                    if (iTemp == 0) {
                        str = "短信指令参数有误，无法发送";
                    } else if (iTemp == 1) {
                        str = "短信指令已接收，准备启动发送";
                    } else if ((iTemp == 2) || (iTemp == 4)) {
                        str = "短信发送结果：发送失败";
                    } else if (iTemp == 3) {
                        str = "短信发送结果：发送成功";
                    }
                    mainFrame.showInfo(str);
                    _serialIndex = 0;
                    return;

                case 0x0E: //接收短信
                    str = "\r\n收到短信：" + new Date() + "\r\n";
                    byte b;
                    b = rcvBuf[index++];
                    if (b == 0x01) {
                        str += "短信类型：中文";
                    } else if (b == 0x02) {
                        str += "短信类型：英文";
                    } else {
                        str += "短信类型：数据";
                    }
                    str += "\r\n";
                    iTemp = rcvBuf[index++]; //接收号码长度;

                    String strPhoneNum = new String(rcvBuf, index, iTemp);
                    str += "电话号码：" + strPhoneNum;
                    index += iTemp;
                    //内容长度
                    dataLen = rcvBuf[index++];

                    str += "\r\n短信内容：";
                    String smsContent = "";
                    if (b == 0x01) {
                        if (rcvBuf[index] == 0x06) {
                            index++;
                            index += 6;
                        }
                        //smsContent = this.UnicodeBytesToString(rcvBuf, index, dataLen);
                        smsContent = new String(rcvBuf, index, dataLen);
                        str += smsContent + "\r\n";
                    } else if (b == 2) {
                        smsContent = new String(rcvBuf, index, dataLen);
                        str += smsContent + "\r\n";
                    } else {
                        for (int i = 0; i < dataLen; i++) {
                            b = rcvBuf[index++];
                            smsContent += String.format("%02X", b) + " ";
                        }
                        str += smsContent + "\r\n";
                    }
                    mainFrame.showInfo(str);
                    _serialIndex = 0;
                    return;
                case 0x12:
                    if (rcvBuf[index] == 0) {
                        mainFrame.showInfo("Error\r\n");
                    } else if (rcvBuf[index] == 1) {
                        mainFrame.showInfo("OK\r\nSystem Will Restart!\r\n");
                    } else {
                        mainFrame.showInfo("OK\r\n");
                    }
                    _serialIndex = 0;
                    return;
            }
        }
    }
}
